home *** CD-ROM | disk | FTP | other *** search
/ Amiga Developer CD 2.1 / Amiga Developer CD v2.1.iso / Reference / Amiga_Mail_Vol2 / Archives / Plain / ma91 / setfunc / SetFunc.txt < prev   
Encoding:
Text File  |  1991-04-15  |  27.6 KB  |  798 lines

  1. (c)  Copyright 1991 Commodore-Amiga, Inc.   All rights reserved.
  2. The information contained herein is subject to change without notice,
  3. and is provided "as is" without warranty of any kind, either expressed
  4. or implied.  The entire risk as to the use of this information is
  5. assumed by the user.
  6.  
  7.  
  8.  
  9.  
  10. Using SetFunction() in a Debugger
  11.  
  12.  
  13. By Ewout Walraven
  14.  
  15.  
  16.  
  17. The Amiga OS consists of a set of libraries (and devices), which reside 
  18. in ROM or on disk.  These libraries provide a set of routines which are 
  19. shared by the Amiga tasks (hence the name shared library). 
  20.  
  21. The way in which an Amiga library is organized allows a programmer to 
  22. change where the system looks for a library routine.  Exec provides a 
  23. function to do this: SetFunction().  The SetFunction() routine redirects 
  24. a library function call to an application-supplied function (Although 
  25. this article doesn't address it, SetFunction() can also be used on Exec 
  26. devices).  The SetPatch utility uses SetFunction().  SetPatch is a 
  27. program which replaces some OS routines with improved ones, primarily to 
  28. fix bugs in ROM libraries. 
  29.  
  30. Normally, programs should not attempt to ``improve'' library functions.  
  31. Because most programmers do not know exactly what system library 
  32. functions do internally, OS patches can do more harm than good. However, 
  33. a useful place to use SetFunction() is in a debugger.  Using 
  34. SetFunction(), a debugger can reroute library calls to a debugging 
  35. function.  The debugging function can inspect the arguments to a library 
  36. function call before calling the original library routine (if everything 
  37. is OK).  Such a debugging function doesn't do any OS patching, it  
  38. merely inspects.  
  39.  
  40. SetFunction() is also useful for testing an application under conditions 
  41. it does not encounter normally.  For example, a debugging program can 
  42. force a program's memory allocations to fail or prevent a program's 
  43. window from opening.  This allows a programmer to find bugs that only 
  44. arise under special circumstances.  Some programs that use SetFunction() 
  45. for debugging purposes are IO_Torture, Memoration and MungWall.  A real 
  46. watchdog is Wedge, which, as its name implies, allows you to install a 
  47. wedge for practically every function of a standard library and inform 
  48. you about the register values passed to the function.  These types of 
  49. debugging tools helped debug release 2.0 of the OS and found bugs and 
  50. 1.3 dependencies in commercial applications.
  51.  
  52. Although useful, SetFunction()ing library routines poses several 
  53. problems.  First of all, the wedge routine will have to be re-entrant, 
  54. like all Exec library functions.  Secondly, there is always a problem 
  55. with removing the wedge.  If another task has SetFunction()ed the same 
  56. library routine as the debugger (a very real possibility), it is not 
  57. normally possible to remove the first wedge, since the other task 
  58. depends on the presence of your task's code.  This would force your task 
  59. to hang around, waiting for the other task(s) to remove their wedges.  
  60. You also need to know when it is safe to unload your debugging code.  
  61. Removing it while another task is executing it will quickly lead to a 
  62. hopelessly crashed system.
  63.  
  64. For those of you who might be thinking about writing down the ROM 
  65. addresses returned by SetFunction() and using them in some other 
  66. programs: Forget It.  The address returned by SetFunction() is only good 
  67. on the current system at the current time.  Blindly jumping into ROM 
  68. will cause your programs to break.
  69.  
  70.  
  71.  
  72. Exec Library Structure
  73.  
  74. When a library is opened for the first time, a library node structure, a 
  75. jump table, and a data area are created in RAM.
  76.  
  77. The library node structure address is the base address of the library.  
  78. OpenLibrary() returns this base address.  The library's jump table, 
  79. which directly precedes the library node in RAM, consists of six byte 
  80. long entries containing a jump instruction (JMP) to a corresponding 
  81. library function.  The jump table is initialized when Exec opens the 
  82. library.  Each function's entry in the jump table (also known as a 
  83. vector) is always a constant (negative) offset from the library base.  
  84. These fixed negative offsets are known as Library Vector Offsets (LVO).  
  85. Note that the first four function vectors are reserved for use by Exec. 
  86. They point to standard library functions for opening, closing, and 
  87. expunging the library, plus there is space reserved for a fourth 
  88. function vector.  The base address of a library is determined 
  89. dynamically when the library is loaded into RAM.  See the Exec 
  90. introduction chapter in the ROM Kernel Manual: Libraries and Devices for 
  91. more information on libraries.
  92.  
  93. The SetFunction() routine replaces an LVO address with a new address 
  94. which points to the wedge routine.  SetFunction() returns the old vector 
  95. address, which the wedge routine can use to call the original library 
  96. function from within the wedge.  Note that if another task 
  97. SetFunction()s the same library function, SetFunction() returns the 
  98. address of your debugging routine (to the second task)  as the old 
  99. vector.  At that point your task can no longer exit since that would 
  100. mean that that other task has an invalid pointer to your function and 
  101. will most likely crash the system when it tries to use your function. 
  102.  
  103. There is a way around this problem.  Instead of SetFunction()ing a 
  104. library function with the address of your wedge code, build your own 
  105. jump table and use the addresses of its entries as arguments to 
  106. SetFunction() calls.  This method allows you to unload your code when 
  107. you want to because if another task SetFunction()s your routine, that 
  108. task will get a pointer to a jump table entry, not your routine.
  109.  
  110. Now when you want to exit, all you need to do is replace the entries in 
  111. your jump table which point to your functions with the original function 
  112. vectors which were returned by SetFunction().  By not freeing the memory 
  113. allocated for the jump table your task can exit any time, regardless of 
  114. other tasks which SetFunction()ed the same library routines.  The other 
  115. task(s) will never know what happened.
  116.  
  117. The next time the debugger is executed, it looks for the jump table it 
  118. left behind and replaces the entries in it with pointers to its own 
  119. functions.  Incidentally, this is an easy way to provide a mechanism to 
  120. determine if your debugging program has already been installed.
  121.  
  122.  
  123.  
  124. Caveats
  125.  
  126. There are some things to keep in mind when using SetFunction().  The 
  127. scheme described above can force a second task to hang around forever if 
  128. it SetFunction()ed a routine before you, since your debugger will not 
  129. normally release its handle on the second task's function.  Whenever 
  130. possible, install jump table based debuggers before any other 
  131. SetFunction()ing program (but after SetPatch of course).
  132.  
  133. Some debuggers interpret the return address of the caller.  When a 
  134. debugger jumps (JMP) to (what it thinks is) the original function, there 
  135. will be no problem.  However, if a debugger performs a JSR to a second 
  136. debugging function which interprets the return address, the second 
  137. debugging function will receive the first debugging function's return 
  138. address (the one that performed the JSR) rather than the return address 
  139. of the application that called the library function in the first place.  
  140. This can confuse the second debugger.  Two good examples of this are 
  141. Scratcher and MungWall, which both SetFunction() FreeMem().  MungWall 
  142. looks at the return address of the caller.  Since Scratcher calls the 
  143. old FreeMem() function with a JSR instruction, it would mislead MungWall 
  144. if run after it.  Preferably, debuggers that interpret the return 
  145. address should be started after other debuggers. 
  146.  
  147.  
  148. Although it is not common, some library functions call other library 
  149. functions and depend on certain scratch registers to contain valid 
  150. values.  SetFunction()ing one of these functions is likely to change the 
  151. values in these scratch registers, leading to problems.  Because these 
  152. dependencies are not always documented, you might innocently run into 
  153. one.  Scratcher is an excellent tool for finding such dependencies.
  154.  
  155. In the past, some system functions did not have a JMP vector in their 
  156. entry in the LVO table.  Instead, the actual function was in the jump 
  157. table.  SetFunction() will not work on such a function.  
  158.  
  159. Any debugging routine should be careful not to call the function it has 
  160. patched with SetFunction(), either directly or indirectly.  Doing so 
  161. will likely cause a stack overflow and crash the machine.  This may seem 
  162. a bit obvious until you consider how easy it is to indirectly call a 
  163. system routine.   Many system functions are not atomic.  They have to 
  164. call lower level system functions.  If you call a higher level system 
  165. functions in the debugging code and you have SetFunction()ed one of the 
  166. routines the high level function uses, the machine will probably crash 
  167. from a stack overflow.
  168.  
  169. Using SetFunction() on disk-based libraries and devices requires a 
  170. little extra care.  Unlike a ROM library, libraries (and devices) loaded 
  171. into RAM can be expunged when memory gets low.  To prevent the system 
  172. from expunging a library (or device) you have SetFunction()ed, either 
  173. keep the library (or device) opened, or use SetFunction() to patch the 
  174. library's expunge function.
  175.  
  176. Remember that when you install a wedge, another program can call it 
  177. almost instantly.  Because of this, the wedge should be completely set 
  178. up before you install it.
  179.  
  180. Note that dos.library is now a standard library and can be 
  181. SetFunction()ed as of V36.  Before V36 you would have to Forbid(), get 
  182. the six original bytes of the entry in the function vector table, 
  183. install the new vector, perform a SumLibrary() and then Permit().
  184.  
  185. If it is necessary to put debugging code into a Forbid() or Disable() 
  186. state, keep it in that state for as little time as possible to limit 
  187. system slowdown.  Remember that you cannot Disable() for more than 250 
  188. microseconds.  Be sure to read the Disable()/Enable() Autodocs before 
  189. using them.
  190.  
  191.  
  192.  
  193. An Example Debugger
  194.  
  195. The usage of SetFunction() is shown by the example debugging program at 
  196. the end of this article, ISpy.  ISpy uses a semaphore to gain access to 
  197. its jump table.  This jump table contains pointers to the wedge 
  198. routines.  When executed, each wedge routine puts a shared lock on the 
  199. semaphore to indicate that the code is being executed.  To get an idea 
  200. of who is calling the debugger entries, ISpy uses a little assembler 
  201. stub to load a4 with the address of the stack of the caller and calls a 
  202. C routine where the actual (simple) argument checking is done.  When 
  203. ISpy is signalled to exit, it tries to get an exclusive lock on the 
  204. semaphore in a Forbid()en state.  If this succeeds, it can safely assume 
  205. its code is not being executed at the moment and can therefore place the 
  206. original function vectors in the jump table and exit, leaving the 
  207. semaphore behind.  This semaphore is also used to check whether ISpy is 
  208. already installed.  If so, the new instance will exit immediately.  
  209. Because of the use of shared semaphore locks, this program will only run 
  210. with V37.  By using a global counter (which is incremented each time a 
  211. function is entered and decremented when it is exited) ISpy can be 
  212. adapted to V33.  Because of the way ISpy is set up, it is very easy to 
  213. add argument checking front ends for functions, and have multiple 
  214. versions of ISpy for different libraries.
  215.  
  216.  
  217.  
  218. Memoration and Scratcher by Bill Hawes.  IO_Torture by Bryce Nesbitt.  
  219. Wedge and DevMon by Carolyn Scheppner.  MungWall by Ewout Walraven 
  220. (inspired by Memwall by Randell Jesup and MemMung by Bryce Nesbitt).
  221.  
  222.  
  223. =======================================================
  224.  
  225. ;/* Execute me to compile with SASC 5.10a
  226. lc -b1 -cfist -d0 -O -v -j73 ispy.c
  227. asm -iINCLUDE: ispy_stubs.asm 
  228. blink from lib:c.o ispy.o ispy_stubs.o LIB lib:amiga.lib lib:lcnb.lib lib:debug.lib SC SD ND DEFINE __main=__tinymain
  229. quit
  230. **      ISpy. AmigaMail SetFunction() example.
  231. **
  232. **      Copyright (c) 1991 Commodore-Amiga, Inc.
  233. **          All Rights Reserved
  234. **
  235. */
  236.  
  237.  
  238. #include <exec/types.h>
  239. #include <exec/execbase.h>
  240. #include <exec/memory.h>
  241. #include <exec/semaphores.h>
  242. #include <dos/dos.h>
  243. #include <libraries/gadtools.h>
  244. #include <string.h>
  245. #include <dos.h>
  246.  
  247. #include <clib/dos_protos.h>
  248. #include <clib/exec_protos.h>
  249. #include <clib/intuition_protos.h>
  250.  
  251. #ifdef LATTICE
  252. int CXBRK(void) { return(0); }  /* Disable Lattice CTRL/C handling */
  253. int chkabort(void) { return(0); }
  254. #endif
  255.  
  256. #define ASM __asm __saveds
  257. #define REG(x) register __## x
  258.  
  259. #ifdef PARALLEL
  260. #define zprintf dprintf
  261. extern VOID     dprintf(STRPTR,...);
  262. #else
  263. #define zprintf kprintf
  264. extern VOID     kprintf(STRPTR,...);
  265. #endif
  266.  
  267. #ifdef DEBUG
  268. #define D(x) x
  269. #else
  270. #define D(x) ;
  271. #endif
  272.  
  273. /* Local protos */
  274. VOID            main(VOID);
  275. BOOL            InstallWedge(VOID);
  276. BOOL            RemoveWedge(VOID);
  277. struct JumpTable *GetJumpTable(UBYTE *);
  278.  
  279. /* Assembler stubs will return a pointer to the caller's stack in a4.
  280.  * The only system function at this moment using a4 is the workbench.library
  281.  * AddAppIconA() function.
  282.  */
  283. #define ACALLER (0)             /* StackPtr[0] = ACaller, StackPtr[1] = saved A6 in stub */
  284. #define CCALLER (2)             /* StackPtr[2] = CCaller */
  285.  
  286. /* The number of 'replacement' functions */
  287. #define NUMBEROFFUNCTIONS (4)
  288.  
  289. /* prototypes for the functions to be SetFunction()'ed. */
  290.  
  291. /* intuition.library */
  292. struct Screen  *(*ASM oldOpenScreen) (REG(a0) struct NewScreen *, 
  293.                                       REG(a6) struct Library *);
  294. struct Window  *(*ASM oldOpenWindowTagList) (REG(a0) struct NewWindow *, 
  295.                                              REG(a1) struct TagItem *, 
  296.                                              REG(a6) struct Library *);
  297. struct Screen  *ASM newOpenScreen(REG(a0) struct NewScreen *, 
  298.                                   REG(a4) ULONG *, 
  299.                                   REG(a6) struct Library *);
  300. struct Window  *ASM newOpenWindowTagList(REG(a0) struct NewWindow *, 
  301.                                          REG(a1) struct TagItem *, 
  302.                                          REG(a4) ULONG *, 
  303.                                          REG(a6) struct Library *);
  304.  
  305. /* exec.library */
  306. VOID(*ASM oldFreeMem) (REG(a1) VOID *, 
  307.                        REG(d0) ULONG, 
  308.                        REG(a6) struct Library *);
  309. VOID ASM        newFreeMem(REG(a1) VOID *, 
  310.                            REG(d0) ULONG, 
  311.                            REG(a4) ULONG *, 
  312.                            REG(a6) struct Library *);
  313.  
  314. /* graphics.library */
  315. VOID(*ASM oldSetFont) (REG(a1) struct RastPort *, 
  316.                        REG(a0) struct TextFont *, 
  317.                        REG(a6) struct Library *);
  318. VOID ASM        newSetFont(REG(a1) struct RastPort *, 
  319.                            REG(a0) struct TextFont *, 
  320.                            REG(a4) ULONG *, 
  321.                            REG(a6) struct Library *);
  322.  
  323. /* Assembler Stubs */
  324. extern          OpenScreenStub();
  325. extern          OpenWindowTagListStub();
  326. extern          FreeMemStub();
  327. extern          SetFontStub();
  328.  
  329. /* The LVO's to use from amiga.lib */
  330. extern          LVOOpenScreen;
  331. extern          LVOOpenWindowTagList;
  332. extern          LVOFreeMem;
  333. extern          LVOSetFont;
  334.  
  335. extern struct ExecBase *SysBase;
  336. struct IntuitionBase *IntuitionBase;
  337. struct GfxBase *GfxBase;
  338.  
  339. /* Use a table and an array to make it a little more generic and easier to
  340.  * add functions.
  341.  */
  342. struct LVOTable
  343. {
  344.     LONG            lt_LVO;
  345.     struct Library *lt_LibBase;
  346.     ULONG           lt_oldFunction;
  347.     ULONG           lt_newFunction;
  348. };
  349.  
  350. struct LVOTable LVOArray[] =
  351. {
  352.     {&LVOOpenScreen, (struct Library *) &IntuitionBase, 
  353.         &oldOpenScreen, 
  354.         &OpenScreenStub},
  355.     {&LVOOpenWindowTagList, (struct Library *) &IntuitionBase, 
  356.                         &oldOpenWindowTagList, &OpenWindowTagListStub},
  357.     {&LVOFreeMem, (struct Library *) & SysBase, &oldFreeMem, &FreeMemStub},
  358.     {&LVOSetFont, (struct Library *) & GfxBase, &oldSetFont, &SetFontStub},
  359. };
  360.  
  361. struct JumpTable
  362. {
  363.     struct SignalSemaphore jt_Semaphore;
  364.     UWORD           pad_word;
  365.     struct Task    *jt_Owner;
  366.     UBYTE           jt_Function[NUMBEROFFUNCTIONS * 6];
  367. };
  368.  
  369. /* Strings */
  370. /* The name this JumpTable/Semaphore will get. */
  371. static UBYTE   *JTName = "ISpy-MiscJumpTable";
  372.  
  373. static UBYTE   *VersTag = "\0$VER: ISpy 37.4 (21.3.91)";
  374. static UBYTE   *VerTitle = "Ispy 37.4";
  375. static UBYTE   *Copyright = "Copyright (c) 1991 Commodore-Amiga, Inc.\n";
  376. static UBYTE   *CBreak = "CTRL-C or BREAK to exit...\n";
  377. VOID 
  378. main(VOID)
  379. {
  380.  
  381.     Write(Output(), (STRPTR) VerTitle, strlen((STRPTR) VerTitle));
  382.     Write(Output(), Copyright, strlen(Copyright));
  383.  
  384.     if (SysBase->LibNode.lib_Version > 36)
  385.     {
  386.         if (IntuitionBase = OpenLibrary("intuition.library", 37))
  387.         {
  388.             if (GfxBase = OpenLibrary("graphics.library", 37))
  389.             {
  390.                 if (InstallWedge())
  391.                 {
  392.                     Write(Output(), CBreak, strlen(CBreak));
  393.                     Wait(SIGBREAKF_CTRL_C);
  394.                     RemoveWedge();
  395.                 }
  396.                 CloseLibrary(GfxBase);
  397.             }
  398.             else
  399.                 Write(Output(), "Couldn't open graphics.library\n", 31);
  400.             CloseLibrary(IntuitionBase);
  401.         }
  402.         else
  403.             Write(Output(), "Couldn't open intuition.library\n", 32);
  404.     }
  405.     else
  406.         Write(Output(), "Requires at least Kickstart 2.04\n", 33);
  407. }
  408.  
  409.  
  410. BOOL 
  411. InstallWedge(VOID)
  412. {
  413.     struct JumpTable *jumptable;
  414.     ULONG          *addressptr;
  415.     UCOUNT          i, j;
  416.  
  417.     Forbid();
  418.  
  419.     /* Get pointer to JumpTable. Create it if necessary */
  420.     if (jumptable = GetJumpTable(JTName))
  421.     {
  422.         /* Try to get exclusive lock on semaphore, in case it already existed. */
  423.         if (AttemptSemaphore((struct SignalSemaphore *) jumptable))
  424.         {
  425.             /* Make sure nobody else has function addresses in the jumptable */
  426.             if (jumptable->jt_Owner == NULL)
  427.             {
  428.                 jumptable->jt_Owner = FindTask(0);
  429.                 /* Don't want to disable any longer than necessary */
  430.                 Disable();
  431.  
  432.                 for (i = 2, j = 0; i < NUMBEROFFUNCTIONS * 6; i += 6, j++)
  433.                 {
  434.                     /* Replace addresses in the jumptable with my own. */
  435.                     addressptr = (ULONG *) ((UBYTE *) jumptable->jt_Function + i);
  436.                     (*((ULONG *) LVOArray[j].lt_oldFunction)) = (ULONG) * addressptr;
  437.                     *addressptr = (ULONG) LVOArray[j].lt_newFunction;
  438.                     D(zprintf("setting table to Function: 0x%lx\n", *addressptr));
  439.                 }
  440.                 Enable();
  441.             }
  442.             else
  443.                 Write(Output(), "Already running.\n", 16);
  444.             ReleaseSemaphore((struct SignalSemaphore *) jumptable);
  445.         }
  446.         else
  447.             Write(Output(), "Can't lock table.\n", 18);
  448.     }
  449.     else
  450.         Write(Output(), "Can't create jumptable\n", 23);
  451.     Permit();
  452.     return ((BOOL) jumptable);
  453. }
  454.  
  455. BOOL 
  456. RemoveWedge(VOID)
  457. {
  458.     struct JumpTable *jumptable;
  459.     ULONG          *addressptr;
  460.     UCOUNT          i, j;
  461.  
  462.     Forbid();
  463.  
  464.     if (jumptable = GetJumpTable(JTName))
  465.     {
  466.         D(zprintf("jumptable @ 0x%lx\n", jumptable));
  467.  
  468.         /* Check if this task owns this jumptable */
  469.         if (jumptable->jt_Owner == FindTask(0))
  470.         {
  471.  
  472.             /* Get the semaphore exclusively.
  473.              * Depending on what got SetFunction()'ed this could take some time.
  474.              * Also note that shared locks are used to indicate the code is
  475.              * being executed and that shared locks can jump ahead of queue'ed
  476.              * exclusive locks, adding to the waittime.
  477.              */
  478.             ObtainSemaphore((struct SignalSemaphore *) jumptable);
  479.  
  480.             Disable();
  481.  
  482.             /* Restore old pointers in jumptable */
  483.  
  484.             for (i = 2, j = 0; i < NUMBEROFFUNCTIONS * 6; i += 6, j++)
  485.             {
  486.                 addressptr = (ULONG *) ((UBYTE *) jumptable->jt_Function + i);
  487.                 *addressptr = (*((ULONG *) LVOArray[j].lt_oldFunction));
  488.                 D(zprintf("setting table to oldFunction: 0x%lx\n", *addressptr));
  489.             }
  490.  
  491.             Enable();
  492.  
  493.             jumptable->jt_Owner = NULL;
  494.             ReleaseSemaphore((struct SignalSemaphore *) jumptable);
  495.         }
  496.     }
  497.  
  498.     Permit();
  499.  
  500.     return (TRUE);
  501. }
  502.  
  503. struct JumpTable *
  504. GetJumpTable(UBYTE * name)
  505. {
  506.     struct JumpTable *jumptable;
  507.     ULONG          *addressptr;
  508.     UWORD          *jmpinstr;
  509.     UBYTE          *jtname;
  510.     UCOUNT          i, j;
  511.  
  512.     /* Not really necessary to forbid again, just to indicate that I don't
  513.      * want another task to create the semaphore while I'm trying to do the
  514.      * same. Here GetJumpTable() is only called from InstallWedge(), so it
  515.      * will just bump the forbid count.
  516.      */
  517.     Forbid();
  518.  
  519.     if (!(jumptable = (struct JumpTable *) FindSemaphore(name)))
  520.     {
  521.         if (jumptable = AllocMem(sizeof(struct JumpTable), MEMF_PUBLIC | MEMF_CLEAR))
  522.         {
  523.             if (jtname = AllocMem(32, MEMF_PUBLIC | MEMF_CLEAR))
  524.             {
  525.  
  526.                 for (i = 0, j = 0; i < NUMBEROFFUNCTIONS * 6; i += 6, j++)
  527.                 {
  528.                     jmpinstr = (UWORD *) ((UBYTE *) jumptable->jt_Function + i);
  529.                     *jmpinstr = 0x4EF9;
  530.  
  531.                     addressptr = (ULONG *) ((UBYTE *) jumptable->jt_Function + i + 2);
  532.                     *addressptr = (ULONG) SetFunction(
  533.                         (struct Library *) (*((ULONG *) LVOArray[j].lt_LibBase)), 
  534.                         LVOArray[j].lt_LVO, 
  535.                         (VOID *) ((UBYTE *) jumptable->jt_Function + i));
  536.                 }
  537.  
  538.                 jumptable->jt_Semaphore.ss_Link.ln_Pri = 0;
  539.  
  540.                 strcpy(jtname, name);
  541.                 jumptable->jt_Semaphore.ss_Link.ln_Name = jtname;
  542.                 AddSemaphore((struct SignalSemaphore *) jumptable);
  543.                 /* In 1.2/1.3 AddSemaphore() didn't work properly.
  544.                 ** Under 1.2/1.3, change it to:
  545.                 ** InitSemaphore(jumptable);
  546.                 ** Forbid();
  547.                 ** Enqueue(&SysBase->SemaphoreList, jumptable);
  548.                 ** Permit();
  549.                 */
  550.             }
  551.             else
  552.             {
  553.                 FreeMem(jumptable, sizeof(struct JumpTable));
  554.                 jumptable = NULL;
  555.             }
  556.         }
  557.     }
  558.  
  559.     Permit();
  560.  
  561.     /* If succeeded, you now have a jumptable which entries point to the original
  562.      * library functions. If another task SetFunction()'ed one or more of those
  563.      * already, that task can never go away anymore.
  564.      */
  565.     return (jumptable);
  566. }
  567.  
  568.  
  569. /* Note: if you'd want this to work with 1.3, you wouldn't/couldn't lock the
  570.  * semaphore, but instead would have to use a global to in- and decrement.
  571.  * When exiting, you'd spin around the global counter, waiting for it to reach
  572.  * zero. At that point you'd Disable(), reset the pointers in the jumptable and
  573.  * Enable() again.
  574.  */
  575.  
  576.  
  577. struct Screen  *ASM 
  578. newOpenScreen(REG(a0) struct NewScreen * newscreen, 
  579.               REG(a4) ULONG * stackptr, 
  580.               REG(a6) struct Library * base)
  581. {
  582.     struct SignalSemaphore *jt;
  583.     struct Screen  *screen = NULL;
  584.  
  585.     /* Find the semaphore to lock shared, indicating the routine is being run. */
  586.     /* For speed reasons you may want to cache the pointer to the semaphore
  587.     ** in a global variable */
  588.     if (jt = FindSemaphore(JTName))
  589.     {
  590.         /* Lock shared in 2.0. In 1.3 you'd increment a global counter */
  591.         ObtainSemaphoreShared(jt);
  592.         /* Simple test for valid argument. Could check all the fields too. */
  593.         if (newscreen != NULL)
  594.         {
  595.             screen = (*oldOpenScreen) (newscreen, base);
  596.         }
  597.         else
  598.         {
  599.             ULONG           ACaller = stackptr[ACALLER];
  600.             ULONG           CCaller = stackptr[CCALLER];
  601.  
  602.             Forbid();           /* To make sure the output isn't garbled */
  603.             zprintf("OpenScreen(NULL) by `%s' (at 0x%lx) from A:0x%lx C:0x%lx SP:0x%lx\n",
  604.                     SysBase->ThisTask->tc_Node.ln_Name, 
  605.                     SysBase->ThisTask, 
  606.                     ACaller, 
  607.                     CCaller, 
  608.                     stackptr);
  609.             Permit();
  610.         }
  611.         /* Release shared lock. In 1.3  you'd decrement the global pointer */
  612.         ReleaseSemaphore(jt);
  613.     }
  614.  
  615.     return (screen);
  616. }
  617.  
  618. struct Window  *ASM 
  619. newOpenWindowTagList(REG(a0) struct NewWindow * newwindow, 
  620.                      REG(a1) struct TagItem * tags, 
  621.                      REG(a4) ULONG * stackptr, 
  622.                      REG(a6) struct Library * base)
  623. {
  624.     struct SignalSemaphore *jt;
  625.     struct Window  *window = NULL;
  626.  
  627.  
  628.     if (jt = FindSemaphore(JTName))
  629.     {
  630.         ObtainSemaphoreShared(jt);
  631.         if (newwindow != NULL || tags != NULL)
  632.         {
  633.             window = (*oldOpenWindowTagList) (newwindow, tags, base);
  634.         }
  635.         else
  636.         {
  637.             ULONG           ACaller = stackptr[ACALLER];
  638.             ULONG           CCaller = stackptr[CCALLER];
  639.  
  640.             Forbid();
  641.             zprintf("OpenWindowTagList(NULL,NULL) by `%s' (at 0x%lx) from A:0x%lx C:0x%lx SP:0x%lx\n",
  642.                     SysBase->ThisTask->tc_Node.ln_Name, 
  643.                     SysBase->ThisTask, 
  644.                     ACaller, 
  645.                     CCaller, 
  646.                     stackptr);
  647.             Permit();
  648.         }
  649.         ReleaseSemaphore(jt);
  650.     }
  651.  
  652.     return (window);
  653. }
  654.  
  655.  
  656. VOID ASM 
  657. newFreeMem(REG(a1) VOID * memptr, 
  658.            REG(d0) ULONG size, 
  659.            REG(a4) ULONG * stackptr, 
  660.            REG(a6) struct Library * base)
  661. {
  662.     struct SignalSemaphore *jt;
  663.  
  664.     if (jt = FindSemaphore(JTName))
  665.     {
  666.         ObtainSemaphoreShared(jt);
  667.         if (memptr != NULL && size != 0L)
  668.         {
  669.             (*oldFreeMem) (memptr, size, base);
  670.         }
  671.         else
  672.         {
  673.             ULONG           ACaller = stackptr[ACALLER];
  674.             ULONG           CCaller = stackptr[CCALLER];
  675.  
  676.             Forbid();
  677.             zprintf("FreeMem(0x%lx,%ld) by `%s' (at 0x%lx) from A:0x%lx C:0x%lx SP:0x%lx\n",
  678.                     memptr, size,
  679.                     SysBase->ThisTask->tc_Node.ln_Name, 
  680.                     SysBase->ThisTask, 
  681.                     ACaller, 
  682.                     CCaller, 
  683.                     stackptr);
  684.             Permit();
  685.         }
  686.  
  687.         ReleaseSemaphore(jt);
  688.     }
  689. }
  690.  
  691. VOID ASM 
  692. newSetFont(REG(a1) struct RastPort * rp, 
  693.            REG(a0) struct TextFont * font, 
  694.            REG(a4) ULONG * stackptr, 
  695.            REG(a6) struct Library * base)
  696. {
  697.     struct SignalSemaphore *jt;
  698.  
  699.  
  700.     if (jt = FindSemaphore(JTName))
  701.     {
  702.         ObtainSemaphoreShared(jt);
  703.         if (rp != NULL && font != NULL)
  704.         {
  705.             (*oldSetFont) (rp, font, base);
  706.         }
  707.         else
  708.         {
  709.             ULONG           ACaller = stackptr[ACALLER];
  710.             ULONG           CCaller = stackptr[CCALLER];
  711.  
  712.             Forbid();
  713.             zprintf("SetFont(0x%lx,0x%lx) by `%s' (at 0x%lx) from A:0x%lx C:0x%lx SP:0x%lx\n",
  714.                     rp, font,
  715.                     SysBase->ThisTask->tc_Node.ln_Name, 
  716.                     SysBase->ThisTask, 
  717.                     ACaller, 
  718.                     CCaller, 
  719.                     stackptr);
  720.             Permit();
  721.         }
  722.         ReleaseSemaphore(jt);
  723.     }
  724. }
  725.  
  726.  
  727.  
  728.  
  729.  
  730.  
  731.  
  732. ===================================================================
  733.  
  734.  
  735.  
  736.  
  737.  
  738.  
  739.  
  740.  
  741.  
  742. **
  743. **      ISpy stubs
  744. **
  745. **      Copyright (c) 1991 Commodore-Amiga, Inc.
  746. **          All Rights Reserved
  747. **
  748. **
  749.     INCLUDE "exec/types.i"
  750.  
  751.     SECTION CODE
  752.  
  753.     XREF    _SysBase
  754.  
  755.     XREF    _LVOForbid
  756.     XREF    _LVOPermit
  757.  
  758.     XREF    _newOpenScreen
  759.     XREF    _newOpenWindowTagList
  760.     XREF    _newFreeMem
  761.     XREF    _newSetFont
  762.  
  763.     XDEF    _OpenScreenStub
  764.     XDEF    _OpenWindowTagListStub
  765.     XDEF    _FreeMemStub
  766.     XDEF    _SetFontStub
  767.  
  768.  
  769. _OpenScreenStub:
  770.     movem.l    a4,-(sp)
  771.     lea        4(sp),a4
  772.     jsr        _newOpenScreen
  773.     movem.l    (sp)+,a4
  774.     rts
  775.  
  776. _OpenWindowTagListStub:
  777.     movem.l    a4,-(sp)
  778.     lea        4(sp),a4
  779.     jsr        _newOpenWindowTagList
  780.     movem.l    (sp)+,a4
  781.     rts
  782.  
  783. _FreeMemStub:
  784.     movem.l    a4,-(sp)
  785.     lea        4(sp),a4
  786.     jsr        _newFreeMem
  787.     movem.l    (sp)+,a4
  788.     rts
  789.  
  790. _SetFontStub:
  791.     movem.l    a4,-(sp)
  792.     lea        4(sp),a4
  793.     jsr        _newSetFont
  794.     movem.l    (sp)+,a4
  795.     rts
  796.  
  797.     END
  798.